﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI.HtmlControls;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Configuration;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace GrayParrot.Web.Controls
{
    /// <summary>
    /// 
    /// </summary>
    public static class ControlsHelper
    {
        #region Consts...
        /// <summary>
        /// The CSS key template
        /// </summary>
        public const string cssKeyTemplate = "<link href=\"{0}\" rel=\"stylesheet\" type=\"text/css\" />";
        /// <summary>
        /// The CND jquery URL
        /// </summary>
        public const string cdnJqueryUrl = "http://code.jquery.com/jquery-1.11.1.min.js";
        /// <summary>
        /// The CND jquery UI URL
        /// </summary>
        public const string cdnJqueryUIUrl = "https://code.jquery.com/ui/1.11.1/jquery-ui.min.js";
        /// <summary>
        /// The CDN jquery UI CSS URL
        /// </summary>
        public const string cdnJqueryUICssUrl = "http://code.jquery.com/ui/1.11.1/themes/smoothness/jquery-ui.css";
        /// <summary>
        /// The CDN timepicker CSS URL
        /// </summary>
        public const string cdnTimepickerCssUrl = "//cdnjs.cloudflare.com/ajax/libs/jquery-ui-timepicker-addon/1.4.5/jquery-ui-timepicker-addon.min.css";
        /// <summary>
        /// The CDN timepicker js URL
        /// </summary>
        public const string cdnTimepickerJsUrl = "//cdnjs.cloudflare.com/ajax/libs/jquery-ui-timepicker-addon/1.4.5/jquery-ui-timepicker-addon.min.js";
        /// <summary>
        /// The js jquery datetimepicker
        /// </summary>
        public const string jsJqueryDatetimepicker = "TradingTool.Web.Controls.Resources.jquery.datetimepicker.js";
        /// <summary>
        /// The CSS jquery datetimepicker
        /// </summary>
        public const string cssJqueryDatetimepicker = "TradingTool.Web.Controls.Resources.jquery.datetimepicker.css";
        /// <summary>
        /// The CDN table CSS URL
        /// </summary>
        public const string cdnTableCssUrl = "//cdn.datatables.net/1.10.2/css/jquery.dataTables.min.css";
        /// <summary>
        /// The CDN data tables URL
        /// </summary>
        public const string cdnDataTablesUrl = "//cdn.datatables.net/1.10.2/js/jquery.dataTables.min.js";
        /// <summary>
        /// The CDN table tools CSS URL
        /// </summary>
        public const string cdnTableToolsCssUrl = "//cdn.datatables.net/tabletools/2.2.2/css/dataTables.tableTools.css";
        /// <summary>
        /// The CDN table tools URL
        /// </summary>
        public const string cdnTableToolsUrl = "//cdn.datatables.net/tabletools/2.2.2/js/dataTables.tableTools.min.js";
        /// <summary>
        /// The CDN jquery key
        /// </summary>
        public const string cdnJqueryKey = "CDNJQUERY";
        /// <summary>
        /// The CDN jquery UI key
        /// </summary>
        public const string cdnJqueryUIKey = "CDNJQUERYUI";
        /// <summary>
        /// The CDN jquery UI CSS key
        /// </summary>
        public const string cdnJqueryUICssKey = "CDNJQUERYCSS";
        /// <summary>
        /// The CDN data tables key
        /// </summary>
        public const string cdnDataTablesKey = "CDNDATATABLES";
        /// <summary>
        /// The data tables block key
        /// </summary>
        public const string dataTablesBlockKey = "DATATABLESBLOCK";
        /// <summary>
        /// The CDN table tools key
        /// </summary>
        public const string cdnTableToolsKey = "CDNTABLETOOLS";
        /// <summary>
        /// The CDN table tools CSS key
        /// </summary>
        public const string cdnTableToolsCssKey = "CDNTABLETOOLSCSS";
        /// <summary>
        /// The CDN table CSS key
        /// </summary>
        public const string cdnTableCssKey = "CDNTABLECSS";
        /// <summary>
        /// The CDN timepicker js key
        /// </summary>
        public const string cdnTimepickerJsKey = "CDNTIMEPICKERJS";
        /// <summary>
        /// The CDN timepicker CSS key
        /// </summary>
        public const string cdnTimepickerCssKey = "CDNTIMEPICKERCSS";
        /// <summary>
        /// The column filter emb js
        /// </summary>
        public const string columnFilterEmbJs = "TradingTool.Web.Controls.Resources.jquery.dataTables.columnFilter.js";
        /// <summary>
        /// The jquery validate key
        /// </summary>
        public const string jqueryValidateKey = "TradingTool.Web.Controls.Resources.jquery.validate.js";
        /// <summary>
        /// The jquery jeditable key
        /// </summary>
        public const string jqueryJeditableKey = "TradingTool.Web.Controls.Resources.jquery.jeditable.js";
        /// <summary>
        /// The jquery data tables editable key
        /// </summary>
        public const string jqueryDataTablesEditableKey = "TradingTool.Web.Controls.Resources.jquery.dataTables.editable.js";
        /// <summary>
        /// The JQDT key
        /// </summary>
        public const string jqdtKey = "TradingTool.Web.Controls.Resources.JQDT.js";
        /// <summary>
        /// The copy TT BTN key
        /// </summary>
        public const string copyTTBtnKey = "TradingTool.Web.Controls.Resources.copy_csv_xls_pdf.swf";
        /// <summary>
        /// The data entry CSS
        /// </summary>
        public const string dataEntryCss = "TradingTool.Web.Controls.Resources.DataEntry.css";
        /// <summary>
        /// The jquery validate additional key
        /// </summary>
        public const string jqueryValidateAdditionalKey = "TradingTool.Web.Controls.Resources.additional-methods.js";
        /// <summary>
        /// The filter list key
        /// </summary>
        public const string filterListKey = "TradingTool.Web.Controls.Resources.filterList.js";
        /// <summary>
        /// The multiple select table CSS key
        /// </summary>
        public const string multipleSelectTableCssKey = "MULTIPLESELECTTABLECSS";
        /// <summary>
        /// The multiple select table CSS
        /// </summary>
        public const string multipleSelectTableCss = "TradingTool.Web.Controls.Resources.TableCSSCode.css";

        #region Search Highligth...
        /// <summary>
        /// The search highlight js key
        /// </summary>
        public const string searchHighlightJsKey = "TradingTool.Web.Controls.Resources.dataTables.searchHighlight.js";
        /// <summary>
        /// The search highlight CSS key
        /// </summary>
        public const string searchHighlightCssKey = "TradingTool.Web.Controls.Resources.dataTables.searchHighlight.css";
        /// <summary>
        /// The cdnsearch highlight key
        /// </summary>
        public const string cdnsearchHighlightKey = "CDNSEARCHHIGHLIGHT";
        /// <summary>
        /// The cdnsearch highlight CSS key
        /// </summary>
        public const string cdnsearchHighlightCssKey = "CDNSEARCHHIGHLIGHTCSS";
        /// <summary>
        /// The cdnjquery highlight key
        /// </summary>
        public const string cdnjqueryHighlightKey = "CDNJQUERYHIGHLIGHT";
        /// <summary>
        /// The cdnsearch highlight key URL
        /// </summary>
        public const string cdnsearchHighlightUrl = "//cdn.datatables.net/plug-ins/3cfcc339e89/features/searchHighlight/dataTables.searchHighlight.min.js";
        /// <summary>
        /// The cdnsearch highlight CSS key URL
        /// </summary>
        public const string cdnsearchHighlightCssUrl = "//cdn.datatables.net/plug-ins/3cfcc339e89/features/searchHighlight/dataTables.searchHighlight.css";
        /// <summary>
        /// The cdnjquery highlight URL
        /// </summary>
        public const string cdnjqueryHighlightUrl = "//bartaz.github.io/sandbox.js/jquery.highlight.js";

        /// <summary>
        /// The CND bootstrap CSS key
        /// </summary>
        public const string cndBootstrapCssKey = "BootstrapCssKey";
        /// <summary>
        /// The CDN bootstrap CSS
        /// </summary>
        public const string cdnBootstrapCssURL = "//cdn.datatables.net/plug-ins/1.10.7/integration/bootstrap/3/dataTables.bootstrap.css";
        /// <summary>
        /// The CND bootstrap JS key
        /// </summary>
        public const string cndBootstrapJSKey = "BootstrapJSKey";
        /// <summary>
        /// The CND bootstrap JS
        /// </summary>
        public const string cndBootstrapJSURL = "//cdn.datatables.net/plug-ins/1.10.7/integration/bootstrap/3/dataTables.bootstrap.js";
        #endregion
        #endregion

        /// <summary>
        /// Add Validation attribute based on property type...
        /// </summary>
        /// <param name="tag">the html tag to which add the attribute</param>
        /// <param name="propertyType">the type of property</param>
        /// <param name="required">flag for required field</param>
        public static void AddAttributes(HtmlControl tag, Type propertyType, bool required = false)
        {
            if (required)
            {
                tag.Attributes.Add("data-rule-required", "true");
            }

            if (propertyType.IsEnum)
            {
                return;
            }

            switch (Type.GetTypeCode(propertyType))
            {
                case TypeCode.Byte:
                case TypeCode.SByte:
                case TypeCode.Int16:
                case TypeCode.Int32:
                case TypeCode.Int64:
                case TypeCode.UInt16:
                case TypeCode.UInt32:
                case TypeCode.UInt64:
                case TypeCode.Single:
                case TypeCode.Double:
                case TypeCode.Decimal:
                    {
                        object minValue = propertyType.InvokeMember("MinValue", BindingFlags.GetField, null, propertyType, null);
                        object maxValue = propertyType.InvokeMember("MaxValue", BindingFlags.GetField, null, propertyType, null);

                        tag.Attributes.Add("data-rule-number", "true");
                        tag.Attributes.Add("data-rule-range", string.Format("{0},{1}", minValue, maxValue));
                    }
                    break;
                case TypeCode.Char:
                    tag.Attributes.Add("data-rule-digits", "true");
                    tag.Attributes.Add("data-rule-maxlength", "1");
                    break;
                case TypeCode.String:
                    //tag.Attributes.Add("data-rule-alphanumeric", "true");
                    break;
                case TypeCode.Boolean:
                    break;
                case TypeCode.DateTime:
                    tag.Attributes.Add("data-rule-date", "true");
                    break;
                case TypeCode.DBNull:
                    break;
                case TypeCode.Empty:
                    break;
                case TypeCode.Object:
                    if (propertyType == typeof(Guid))
                    {
                        tag.Attributes.Add("data-rule-pattern", @"^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$");
                    }
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// Add Validation attribute based on property type...
        /// </summary>
        /// <param name="tag">the html tag to which add the attribute</param>
        /// <param name="propertyType">the type of property</param>
        /// <param name="required">flag for required field</param>
        public static string AddAttributes(Type propertyType, bool required = false)
        {
            string retValue = string.Empty;

            //if (required)
            //{
            //    retValue = "data-rule-required=\"true\" ";
            //}

            retValue = string.Format("data-rule-required=\"{0}\" ", required);

            switch (Type.GetTypeCode(propertyType))
            {
                case TypeCode.Byte:
                case TypeCode.SByte:
                case TypeCode.Int16:
                case TypeCode.Int32:
                case TypeCode.Int64:
                case TypeCode.UInt16:
                case TypeCode.UInt32:
                case TypeCode.UInt64:
                case TypeCode.Single:
                case TypeCode.Double:
                case TypeCode.Decimal:
                    {
                        object minValue = propertyType.InvokeMember("MinValue", BindingFlags.GetField, null, propertyType, null);
                        object maxValue = propertyType.InvokeMember("MaxValue", BindingFlags.GetField, null, propertyType, null);

                        retValue += "data-rule-number=\"true\" ";
                        retValue += string.Format("data-rule-range=\"{0},{1}\" ", minValue, maxValue);
                    }
                    break;
                case TypeCode.Char:
                    retValue += "data-rule-digits=\"true\" ";
                    retValue += "data-rule-maxlength=\"1\" ";
                    break;
                case TypeCode.String:
                    //retValue += "data-rule-alphanumeric=\"true\" ";
                    break;
                case TypeCode.Boolean:
                    break;
                case TypeCode.DateTime:
                    retValue += "data-rule-date=\"true\" ";
                    break;
                case TypeCode.DBNull:
                    break;
                case TypeCode.Empty:
                    break;
                case TypeCode.Object:
                    if (propertyType == typeof(Guid))
                    {
                        retValue += "data-rule-pattern=\"^(\\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\\}{0,1})$\" ";
                    }
                    break;
                default:
                    break;
            }

            return retValue;
        }

        public static bool CheckBaseType(Type propertyType)
        {
            bool retValue = false;

            switch (Type.GetTypeCode(propertyType))
            {
                case TypeCode.Byte:
                case TypeCode.SByte:
                case TypeCode.Int16:
                case TypeCode.Int32:
                case TypeCode.Int64:
                case TypeCode.UInt16:
                case TypeCode.UInt32:
                case TypeCode.UInt64:
                case TypeCode.Single:
                case TypeCode.Double:
                case TypeCode.Decimal:
                case TypeCode.Char:
                case TypeCode.String:
                case TypeCode.Boolean:
                case TypeCode.DateTime:
                case TypeCode.DBNull:
                case TypeCode.Empty:
                    retValue = true;
                    break;
                case TypeCode.Object:
                    if (propertyType == typeof(Guid))
                    {
                        retValue = true;
                    }
                    break;
            }

            return retValue;
        }

        public static bool CheckBaseType(string propertyType)
        {
            bool retValue = false;

            switch (propertyType.ToLower())
            {
                case "guid":
                case "number":
                case "decimal":
                case "text":
                case "date-range":
                case "bool":
                case "object":
                    retValue = true;
                    break;
            }

            return retValue;
        }

        public static string SplitCamelCase(this string str)
        {
            return Regex.Replace(
                Regex.Replace(
                    str,
                    @"(\P{Ll})(\P{Ll}\p{Ll})",
                    "$1 $2"
                ),
                @"(\p{Ll})(\P{Ll})",
                "$1 $2"
            );
        }

        //public static string SplitCamelCase2(this string str)
        //{
        //    return Regex.Replace(str, "([A-Z])", " $1").Trim();
        //}

        public static int NthOccurenceOf(this String s, char c, int n)
        {
            int result = -1;
            MatchCollection mc = Regex.Matches(s, c.ToString());
            if (mc.Count >= n)
            {
                result = mc[n - 1].Index;
            }
            return result;
        }

        public static string ReplaceCharAt(this string s, int pos, string c)
        {
            if (pos == -1) return s;
            else return s.Substring(0, pos) + c + s.Substring(pos + 1);
        }

        //public static string GetCdnUrl(string sectionName, string cdnKey)
        //{
        //    string retValue = string.Empty;

        //    var section = ConfigurationManager.GetSection(sectionName);
        //    if (section != null)
        //    {
        //        var m_entity = (section as EntityDefinitionSection).Cdns[cdnKey];

        //        if (m_entity != null)
        //        {
        //            retValue = m_entity.Url;
        //        }
        //        else
        //        {
        //            FieldInfo m_fi = typeof(ControlsHelper).GetFields().Where(f => f.Name.Equals(string.Format("{0}Url", cdnKey), StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();

        //            retValue = m_fi.GetRawConstantValue().ToString();
        //        }
        //    }

        //    return retValue;
        //}

        /// <summary>
        /// Settings up libraries.
        /// </summary>
        /// <param name="page">The page.</param>
        public static void SettingUpLibraries(Page page)
        {
            RegisterHeadClientScriptInclude(page, ControlsHelper.cdnJqueryKey, ControlsHelper.cdnJqueryUrl);
            RegisterHeadClientScriptInclude(page, ControlsHelper.cdnJqueryUIKey, ControlsHelper.cdnJqueryUIUrl);
            RegisterHeadClientScriptLinkBlock(page, ControlsHelper.cdnJqueryUICssKey, ControlsHelper.cdnJqueryUICssUrl);

            //if (!page.ClientScript.IsClientScriptIncludeRegistered(page.GetType(), ControlsHelper.cdnJqueryKey))
            //{
            //    page.ClientScript.RegisterClientScriptInclude(page.GetType(), ControlsHelper.cdnJqueryKey, ControlsHelper.cdnJqueryUrl);
            //}

            //if (!page.ClientScript.IsClientScriptIncludeRegistered(page.GetType(), ControlsHelper.cdnJqueryUIKey))
            //{
            //    page.ClientScript.RegisterClientScriptInclude(page.GetType(), ControlsHelper.cdnJqueryUIKey, ControlsHelper.cdnJqueryUIUrl);
            //}

            //if (!page.ClientScript.IsClientScriptIncludeRegistered(page.GetType(), ControlsHelper.cdnJqueryUICssKey))
            //{
            //    string css = string.Format(ControlsHelper.cssKeyTemplate, ControlsHelper.cdnJqueryUICssUrl);

            //    page.ClientScript.RegisterClientScriptBlock(page.GetType(), ControlsHelper.cdnJqueryUICssKey, css, false);
            //}
        }

        public static void AddScriptInclude(Page page, string key, string url)
        {
            if (!page.ClientScript.IsClientScriptIncludeRegistered(page.GetType(), key))
            {
                page.ClientScript.RegisterClientScriptInclude(page.GetType(), key, url);
            }
        }

        public static void AddLinkBlock(Page page, string key, string url)
        {
            if (!page.ClientScript.IsClientScriptIncludeRegistered(page.GetType(), key))
            {
                string css = string.Format(ControlsHelper.cssKeyTemplate, url);

                page.ClientScript.RegisterClientScriptBlock(page.GetType(), key, css, false);
            }
        }

        public static void AddWebResource(Page page, string key)
        {
            if (!page.ClientScript.IsClientScriptIncludeRegistered(page.GetType(), key))
            {
                string m_resUrl = page.ClientScript.GetWebResourceUrl(page.GetType(), key);
                page.ClientScript.RegisterClientScriptInclude(page.GetType(), key, m_resUrl);
            }
        }

        /// <summary>
        /// Registers the client script include in the head section.  If the
        /// same ID is sent, the source file is replaced with the new one.
        /// </summary>
        /// <param name="page">The page.</param>
        /// <param name="id">The control ID to make sure there aren't two
        /// registered under the same ID</param>
        /// <param name="src">The file name.</param>
        public static void RegisterHeadClientScriptInclude(Page page, string id, string src)
        {
            HtmlGenericControl si = null;
            foreach (Control c in page.Header.Controls)
            {
                if (c.ID != id) continue;
                si = (HtmlGenericControl)c;
                break;
            }
            if (si == null)
            {
                si = new HtmlGenericControl { ID = id, TagName = "script" };
                si.Attributes.Add("type", "text/javascript");
                si.Attributes.Add("src", src);
            }
            else
            {
                si.Attributes["src"] = src;
            }
            page.Header.Controls.Add(si);
            page.Header.Controls.Add(new LiteralControl("\r\n"));
        }

        /// <summary>
        /// Registers the client script code block in the head section of the page.
        /// </summary>
        /// <param name="page">The page.</param>
        /// <param name="id">The id.</param>
        /// <param name="code">The code.</param>
        public static void RegisterHeadClientScriptBlock(Page page, string id, string code)
        {
            HtmlGenericControl si = null;
            foreach (Control c in page.Header.Controls)
            {
                if (c.ID != id) continue;
                si = (HtmlGenericControl)c;
                break;
            }
            if (si == null)
            {
                si = new HtmlGenericControl { ID = id, TagName = "script" };
                si.Attributes.Add("type", "text/javascript");
            }
            si.InnerText = code;
            page.Header.Controls.Add(si);
            page.Header.Controls.Add(new LiteralControl("\r\n"));
        }

        /// <summary>
        /// Registers the client script code block in the head section of the page.
        /// </summary>
        /// <param name="page">The page.</param>
        /// <param name="id">The id.</param>
        /// <param name="code">The code.</param>
        public static void RegisterHeadClientScriptLinkBlock(Page page, string id, string url)
        {
            HtmlLink si = null;
            foreach (Control c in page.Header.Controls)
            {
                if (c.ID != id) continue;
                si = (HtmlLink)c;
                break;
            }
            if (si == null)
            {
                si = new HtmlLink { ID = id, Href = url };
                si.Attributes.Add("rel", "stylesheet");
                si.Attributes.Add("type", "text/css");
            }

            page.Header.Controls.Add(si);
            page.Header.Controls.Add(new LiteralControl("\r\n"));
        }

        public static string TypeSymbol(this Unit obj)
        {
            string retValue = "px";

            if (obj.Type == UnitType.Percentage)
            {
                retValue = "%";
            }

            return retValue;
        }
    }
}
